/*
 * bind.h
 *
 *  Created on: 2008-9-12
 *      Author: fanliangliang
 */

#ifndef BIND_H_
#define BIND_H_

#include "config.h"

BEGIN_NAMESPACE_TOXIC

namespace detail {

	template <typename R>
	struct nullary_function {
		typedef R result_type;
	};


	template <typename F, typename A1>
	class binder1 : public nullary_function<typename F::result_type> {
	public:
		binder1(const F& f, const A1& a1)
		:_f(f), _a1(a1) {}
		typename F::result_type operator()() const {
			return _f(_a1);
		}
	protected:
		F _f;
		A1 _a1;
	};


	template <typename F, typename A1, typename A2>
	class binder2 : public nullary_function<typename F::result_type> {
	public:
		binder2(const F& f, const A1& a1, const A2& a2)
		:_f(f), _a1(a1), _a2(a2) {}
		typename F::result_type operator()() const {
			return _f(_a1, _a2);
		}
	protected:
		F _f;
		A1 _a1;
		A2 _a2;
	};


	template <typename R, typename B1, typename A1>
	class binder1_f : public nullary_function<R> {
	public:
		binder1_f(R (*f)(B1), A1 a1)
		:_f(f), _a1(a1) {}
		R operator()() const {
			return _f(_a1);
		}
	protected:
		R (*_f)(B1);
		A1 _a1;
	};


	template <typename R, typename B1, typename B2, typename A1, typename A2>
	class binder2_f : public nullary_function<R> {
	public:
		binder2_f(R (*f)(B1, B2), A1 a1, A2 a2)
		:_f(f), _a1(a1), _a2(a2) {}
		R operator()() const {
			return _f(_a1, _a2);
		}
	protected:
		R (*_f)(B1, B2);
		A1 _a1;
		A2 _a2;
	};


	template <typename R, typename A1>
	class binder1_m : public nullary_function<R> {
	public:
		binder1_m(R (A1::*f)(), A1& a1)
		:_f(f), _a1(&a1) {}
		binder1_m(R (A1::*f)(), A1* a1)
		:_f(f), _a1(a1) {}
		R operator()() {
			return (_a1->*_f)();
		}
	protected:
		R (A1::*_f)();
		A1* _a1;
	};


	template <typename R, typename B1, typename A1>
	class binder2_m : public nullary_function<R> {
	public:
		binder2_m(R (A1::*f)(B1), A1& a1, B1 b1)
		:_f(f), _a1(&a1), _b1(b1) {}
		binder2_m(R (A1::*f)(B1), A1* a1, B1 b1)
		:_f(f), _a1(a1), _b1(b1) {}
		R operator()() {
			return (_a1->*_f)(_b1);
		}
	protected:
		R (A1::*_f)(B1);
		A1* _a1;
		B1 _b1;
	};

} // namespace detail


template <typename F, typename A1>
inline detail::binder1<F, A1>
bind(const F& f, const A1& a1) {
	return detail::binder1<F, A1>(f, A1(a1));
}

template <typename F, typename A1, typename A2>
inline detail::binder2<F, A1, A2>
bind(const F& f, const A1& a1, const A2& a2) {
	return detail::binder2<F, A1, A2>(f, A1(a1), A2(a2));
}

template <typename R, typename B1, typename A1>
inline detail::binder1_f<R, B1, A1>
bind(R (*f)(B1), A1 a1) {
	return detail::binder1_f<R, B1, A1>(f, a1);
}

template <typename R, typename B1, typename B2, typename A1, typename A2>
inline detail::binder2_f<R, B1, B2, A1, A2>
bind(R (*f)(B1, B2), A1 a1, A2 a2) {
	return detail::binder2_f<R, B1, B2, A1, A2>(f, a1, a2);
}

template <typename R, typename A1>
inline detail::binder1_m<R, A1>
bind(R (A1::*f)(), A1& a1) {
	return detail::binder1_m<R, A1>(f, a1);
}

template <typename R, typename A1>
inline detail::binder1_m<R, A1>
bind(R (A1::*f)(), A1* a1) {
	return detail::binder1_m<R, A1>(f, a1);
}

template <typename R, typename B1, typename A1>
inline detail::binder2_m<R, B1, A1>
bind(R (A1::*f)(B1), A1& a1, B1 b1) {
	return detail::binder2_m<R, B1, A1>(f, a1, b1);
}

template <typename R, typename B1, typename A1>
inline detail::binder2_m<R, B1, A1>
bind(R (A1::*f)(B1), A1* a1, B1 b1) {
	return detail::binder2_m<R, B1, A1>(f, a1, b1);
}

END_NAMESPACE_TOXIC

#endif /* BIND_H_ */
